`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/03/30 09:11:20
// Design Name: 
// Module Name: axi_master_writer
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module axi_master_writer#(
    parameter   axi_data_width          =   512         
    )(
    input   wire                m_axi_aclk      ,       
    input   wire                m_axi_reset     ,
    input   wire                start_write ,
    input   wire    [31:0]      address         ,
    input   wire    [7:0]       burst_length    ,
    input   wire    [2:0]       burst_size      ,
    input   wire    [1:0]       increment_burst ,
    output  reg                 done            ,
    output  reg                 error           ,
    output  reg                 busy            ,
//  data input
    input   wire    [axi_data_width-1:0]        din             ,
    input   wire                din_valid       ,
    output  wire                din_ready       ,
//  AXI4 Write Address Channel
    input   wire                m_axi_awready   ,           
    output  reg                 m_axi_awvalid   ,        
    output  reg     [31:0]      m_axi_awaddr    ,       
    output  wire    [3:0]       m_axi_awid      ,       
    output  reg     [7:0]       m_axi_awlen     ,       
    output  reg     [2:0]       m_axi_awsize    ,       
    output  reg     [1:0]       m_axi_awburst   ,       
    output  wire                m_axi_awlock    ,       
    output  wire    [3:0]       m_axi_awcache   ,       
    output  wire    [2:0]       m_axi_awprot    ,       
    output  wire    [3:0]       m_axi_awqos     ,       
    output  wire    [3:0]       m_axi_awregion  ,       
//  AXI4 Write Data Channel
    input   wire                m_axi_wready    ,           
    output  wire                m_axi_wvalid    ,        
    output  wire    [3:0]       m_axi_wid       ,       
    output  wire    [axi_data_width-1:0]        m_axi_wdata     ,        
    output  wire    [axi_data_width/8-1:0]      m_axi_wstrb     ,        
    output  reg                 m_axi_wlast     ,        
//  AXI4 Write Response Channel
    output  wire                m_axi_bready    ,           
    input   wire                m_axi_bvalid    ,        
    input   wire    [1:0]       m_axi_bresp     ,        
    input   wire    [3:0]       m_axi_bid               
    );
    
    assign  m_axi_awid      =   'd0;
    assign  m_axi_awlock    =   'd0;
    assign  m_axi_awcache   =   'd0;
    assign  m_axi_awprot    =   'd0;
    assign  m_axi_awqos     =   'd0;
    assign  m_axi_awregion  =   'd0;
    
    assign  m_axi_wdata     =   din; 
    assign  m_axi_wstrb     =   64'hffff_ffff_ffff_ffff;
    assign  m_axi_wid       =   'd0;
    assign  din_ready       =   wr_enable ? m_axi_wready : 1'd0;//m_axi_wready;//
    assign  m_axi_wvalid    =   wr_enable ? din_valid : 1'd0;// din_valid;//
    
    assign  m_axi_bready    =   1'd1;

    always @(posedge m_axi_aclk)
        if(m_axi_reset) begin
            m_axi_awaddr    <=  'd0;
            m_axi_awlen     <=  'd0;
            m_axi_awsize    <=  'd0;
            m_axi_awburst   <=  'd0;
        end
        else if(start_write)begin
            m_axi_awaddr    <=  address;
            m_axi_awlen     <=  burst_length;
            m_axi_awsize    <=  burst_size;
            m_axi_awburst   <=  increment_burst;
        end  
    
    localparam  IDLE    =   'd0,
                WR_ADDR =   'd1,
                WR_DATA =   'd2,
                COMPELTE=   'd3,
                ERROR   =   'd4;
    
    reg     [2:0]   state,nx_state;
    reg     [7:0]   cnt_wr;
    reg             wr_enable;
    always @(posedge m_axi_aclk)
        if(m_axi_reset)
            state <= IDLE;
        else 
            state <= nx_state;
    
    always @(*)
        case(state)
            IDLE        :   if(start_write) nx_state = WR_ADDR; else nx_state = IDLE;   
            WR_ADDR     :   if(m_axi_awvalid &m_axi_awready)nx_state = WR_DATA; else nx_state = WR_ADDR;
            WR_DATA     :   if(m_axi_wready & m_axi_wlast & m_axi_wvalid)nx_state = COMPELTE; else nx_state = WR_DATA;  //
            COMPELTE    :   if(m_axi_bvalid & m_axi_bresp == 2'b00)nx_state = IDLE;else if(m_axi_bvalid & m_axi_bresp != 2'b00) nx_state = ERROR; else nx_state = COMPELTE;
            ERROR       :   nx_state = IDLE;
            default     :   nx_state = IDLE;
        endcase
    
    always @(posedge m_axi_aclk)
        case(state)
            WR_ADDR     :   if(m_axi_awvalid & m_axi_awready) m_axi_awvalid   <=  1'd0;else  m_axi_awvalid   <= 1'd1;
            default     :   m_axi_awvalid   <=  1'd0;
        endcase

    always @(*)
        case(state)
            WR_ADDR,WR_DATA     :   wr_enable = 1'd1;
            default    			:   wr_enable = 1'd0;
        endcase 
    
    always @(posedge m_axi_aclk)
        case(state)
            IDLE        :   cnt_wr <= 8'd0;
            WR_ADDR,WR_DATA     :   if(m_axi_wvalid & m_axi_wready) cnt_wr <= cnt_wr + 1'd1;
            default     :   cnt_wr <= 8'd0;
        endcase 

    always @(posedge m_axi_aclk)
        case(state)
           WR_ADDR,WR_DATA :   begin
                                if(m_axi_wready & m_axi_wlast & m_axi_wvalid)
                                    m_axi_wlast <= 1'd0;                                
                                else if(m_axi_wready & (m_axi_awlen == 8'd0))
                                    m_axi_wlast <= 1'd1;
                                else if(m_axi_wready & m_axi_wvalid & (cnt_wr == m_axi_awlen - 1'd1))
                                    m_axi_wlast <= 1'd1;
                                else
                                    m_axi_wlast <= m_axi_wlast;
                            end
            default     :   m_axi_wlast <= 1'd0;
        endcase
    
    always @(posedge m_axi_aclk)
        case(state)
            ERROR       :   error   <= 1'd1;
            default     :   error   <= 1'd0;
        endcase
        
    always @(posedge m_axi_aclk)
        case(state)
            COMPELTE    :   if(m_axi_bvalid) done <= 1'd1;else done <= 1'd0;
			//WR_DATA		: if(m_axi_wready & m_axi_wlast & m_axi_wvalid)done <= 1'd1;else done <= 1'd0;
            default     :   done    <= 1'd0;
        endcase     
    
    always @(posedge m_axi_aclk)
        case(state)
            IDLE    :   busy    <=  1'd0;
            default :   busy    <=  1'd1;//busy    <=  1'd1;
        endcase
endmodule
